/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package estate;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Vector;

/**
 *
 * @author Wlodek
 */
class EstateRadixSort {


      static  List[] kolejkaZliczanych;

      static  int ilosc_kubkow = 0;

    private static void poAtrybutach(Vector<Integer> ilosci){
        for(int i=0;i<ilosci.size();i++){
            ilosc_kubkow=ilosci.get(i);
            kolejkaZliczanych = new LinkedList[ilosc_kubkow];


        }
    }


    public static void EstateRadixSort(ArrayList<Estate> l) {// kod do modyfikacji!!!-prosze wykorzystac polimorfizm

        ilosc_kubkow = 0;

        //po rozkladowe
        ilosc_kubkow = 2;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for (int i = 0; i < ilosc_kubkow; i++) {
            kolejkaZliczanych[i] = new LinkedList();
        }

        for (int i = 0; i < l.size(); i++) {

            if ( l.get(i).rPlaceByCzyRozkladowy() == true) {
                kolejkaZliczanych[0].add(l.get(i));
            } else {
                kolejkaZliczanych[1].add(l.get(i));
            }
        }
        l.clear();
        l.addAll(kolejkaZliczanych[0]);
        l.addAll(kolejkaZliczanych[1]);


        //sortowanie po pietrze
        ilosc_kubkow = 200;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for (int i = 0; i < ilosc_kubkow; i++) {
            kolejkaZliczanych[i] = new LinkedList();
        }

        for (int i = 0; i < l.size(); i++) {
            if ( l.get(i).rPlaceByLiczbaPieter() >= 0 && l.get(i).rPlaceByLiczbaPieter() < 200) {
                kolejkaZliczanych[l.get(i).rPlaceByLiczbaPieter() % ilosc_kubkow].add(l.get(i));
            } else if (l.get(i).rPlaceByLiczbaPieter() >= 200) {
                kolejkaZliczanych[ilosc_kubkow - 1].add(l.get(i));
            } else {
                kolejkaZliczanych[0].add(l.get(i)); //dla uproszczenia przyjmujemy, ze mieszkanie na -1 pietrze jest tyle samo warte co mieszkanie ma parterze
            }
        }
        l.clear();
        for (int i = 0; i < ilosc_kubkow; i++) {
            l.addAll(kolejkaZliczanych[i]);
        }


        //sortowanie po roku budowy
        ilosc_kubkow = 400;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for (int i = 0; i < ilosc_kubkow; i++) {
            kolejkaZliczanych[i] = new LinkedList();
        }

        for (int i = 0; i < l.size(); i++) {
            if ( l.get(i).rPlaceByRokBudowy() - 1900 >= 0) {
                kolejkaZliczanych[ilosc_kubkow - 1 - (l.get(i).rPlaceByRokBudowy() - 1900) % ilosc_kubkow].add(l.get(i)); //algorytm dziala poprawnie do roku 2300
            } else {
                kolejkaZliczanych[0].add(l.get(i)); //przyjmujemy, ze budynki zbudowane przed 1900 rokiem to zabytki
            }
        }
        l.clear();
        for (int i = 0; i < ilosc_kubkow; i++) {
            l.addAll(kolejkaZliczanych[i]);
        }


        //sortowanie po liczbie pokoi/lazienek
        ilosc_kubkow = 60;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for (int i = 0; i < ilosc_kubkow; i++) {
            kolejkaZliczanych[i] = new LinkedList();
        }

        for (int i = 0; i < l.size(); i++) {
            if (l.get(i).rPlaceByliczbaPokoi() >= 0 && l.get(i).rPlaceByliczbaPokoi() < 60) {
                kolejkaZliczanych[ilosc_kubkow - 1 - l.get(i).rPlaceByliczbaPokoi() % ilosc_kubkow].add(l.get(i));
            } else if (l.get(i).rPlaceByliczbaPokoi() >= 60) {
                kolejkaZliczanych[0].add(l.get(i));
            } else {
                kolejkaZliczanych[ilosc_kubkow - 1].add(l.get(i));// nie zwracamy wyjatku w razie bledu, poniewaz komplikowaloby to w znaczny sposob nasza aplikacje
            }
        }
        l.clear();
        for (int i = 0; i < ilosc_kubkow; i++) {
            l.addAll(kolejkaZliczanych[i]);
        }


        //sortowanie po metrazu
        ilosc_kubkow = 50;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for (int i = 0; i < ilosc_kubkow; i++) {
            kolejkaZliczanych[i] = new LinkedList();
        }

        for (int i = 0; i < l.size(); i++) {
            if (l.get(i).rPlaceByMetraz() >= 0 && l.get(i).rPlaceByMetraz() < 1000) {
                kolejkaZliczanych[ilosc_kubkow - ((l.get(i).rPlaceByMetraz() / 20) % ilosc_kubkow) - 1].add(l.get(i));
            } else if (l.get(i).rPlaceByMetraz() >= 1000) {
                kolejkaZliczanych[0].add(l.get(i));
            } else {
                kolejkaZliczanych[ilosc_kubkow - 1].add(l.get(i));// ujemny metraz moglby byc nadużywany w pozycjonowaniu ofert, dlatego wpisujemy go na koniec
            }
        }
        l.clear();
        for (int i = 0; i < ilosc_kubkow; i++) {
            l.addAll(kolejkaZliczanych[i]);
        }


        //sortowanie po cenie
        ilosc_kubkow = 500;
        kolejkaZliczanych = new LinkedList[ilosc_kubkow];
        for (int i = 0; i < ilosc_kubkow; i++) {
            kolejkaZliczanych[i] = new LinkedList();
        }

        for (int i = 0; i < l.size(); i++) {
            if (l.get(i).rPlaceByCena() >= 0 && l.get(i).rPlaceByCena() < 500000) {
                kolejkaZliczanych[(l.get(i).rPlaceByCena()/ 1000) % ilosc_kubkow].add(l.get(i));// algorytm zaklada ze statystycznie bardzo rzadko ceny miekszan sa wieksze niz 500 tys, wtedy bowiem dziala niepoprawnie dla cen
            } else {
                kolejkaZliczanych[ilosc_kubkow - 1].add(l.get(i));// za wysoka lub ujemna cena moglaby byc nadużywana w pozycjonowaniu ofert, dlatego wpisujemy ja na koniec
            }
        }
        l.clear();
        for (int i = 0; i < ilosc_kubkow; i++) {
            l.addAll(kolejkaZliczanych[i]);
        }

    }
}

class PorownanieKaskadoweOfert implements Comparator<Estate> {//modyfikacja ZK

    public int compare(Estate arg0, Estate arg1) {
        int wynik;
        if (((Dekorator) arg0).getTypOferty() == 2) //kolejne sortowanie
        {
            if ((wynik = arg0.compareTo(arg1)) != 0) //Oferta
            {
                return wynik;
            }
        }
        
        return 0;
    }
}

public class Fasada1 {

    private ArrayList<Estate> katalogOfert = new ArrayList<Estate>();
    private ArrayList<User> katalogUsers = new ArrayList<User>();

    private ArrayList<Estate> wyszukaj_m_z_n(int m) {
        ArrayList<Estate> al = new ArrayList<Estate>();
        al.addAll(this.katalogOfert);

        //nasza metoda inteligentnie rozstrzyga czy warto uzywac sortowania pozycyjnego, czy korzystniej uzyc sortowania szybkiego 185

        if (al.size() > 185) {
            EstateRadixSort.EstateRadixSort(al);
        } else {
            Collections.sort((List) al);
        }

        int rozmiar = al.size();
        if (rozmiar > 3) {
            for (int i = 3; i < rozmiar; i++) {
                al.remove(al.get(3));
            }
        }
        return al;
    }
    /**
     * Metoda wcześniej zaimplementowana przez kolegów
     * @param wzorzec
     * @return
     */
    public ArrayList<Estate> wyszukaj(Estate wzorzec) { ///???????
        return null;
    }

    public String zestawOferty(HashMap<String, Object> wz) {//???????????????
        FabrykaAbstrakcyjna f = new FabrykaStandard();
        Estate wzorzec = f.stworzOferte(wz);
        if (katalogOfert == null) {
            katalogOfert = wyszukaj(wzorzec);
        }
        String s = wyszukaj_m_z_n(wz.size() / 15).toString();
        return s;
    }

    public User Szukaj_user(User user) { //propozycja ZK
        int idx;
        if ((idx = katalogUsers.indexOf(user)) != -1) {
            return katalogUsers.get(idx);
        }

        return null;
    }

    public User stworzUsera(HashMap<String, Object> hm) {//propozycja ZK
        UsersFactory uf = new UsersFactory();
        User user = uf.createUser(hm);
        if (Szukaj_user(user) == null) {
            katalogUsers.add(user);
            return user;
        }
        return null;
    }

    public Estate Szukaj_estate(Estate wzorzec) {//propozycja ZK

        int idx;
        if ((idx = katalogOfert.indexOf(wzorzec)) != -1) {
            return katalogOfert.get(idx);
        }
        return null;
    }

    
    public Estate Dodajoferte(HashMap<String, Object> hm1, HashMap<String, Object> hm2) { //propozycja ZK
        FabrykaStandard instance1 = new FabrykaStandard();
        Estate estate =instance1.stworzOferte(hm1);
        UsersFactory instance2 = new UsersFactory();
        User user = instance2.createUser(hm2);
        if ((user=Szukaj_user(user)) != null){
             estate.setUser(user);
          if (Szukaj_estate(estate) == null) {
             user.addEstate(estate);
            katalogOfert.add(estate);
            return estate;
        }}
        return null;
    }

    public String toString(){
        return katalogOfert.toString();
    }


	/* BEGIN Funkcjonalnosć komentarzy */

	private List<Comment> komentarze = new ArrayList<Comment>();

	public List<Comment> getKomentarze()
	{
		return this.komentarze;
	}

	/**
	 * @param comment - obiekt komentarza wyszukany w application beanie
	 */
	public void acceptComment(Comment comment) {
    	comment.setAccepted(true);
    }

	/**
	 * @param comment - obiekt komentarza wyszukany w application beanie
	 * @param cause - powod usuniecia komentarza
	 */
	public void deleteComment(Comment comment, String cause) {
		comment.setCause(cause);
		comment.setDeleted(true);
	}

	/**
	 * @param commentData - dane komentarza<br /> - "title" -> tytul komentarza<br /> - "content" -> tresc komentarza
	 * @param user - obiekt uzytkownika wyszukany w application beanie
	 * @param estate - obiekt klasy Estate wyszukany w application beanie
	 */
	public boolean addComment(Map<String, String> commentData, User user, Estate estate) {
		String title = commentData.get("title");
		String content = commentData.get("content");
		return addComment(title, content, user, estate);

	}

	/**
	 * @param title - tytul komentarza
	 * @param content - tresc komentarza
	 * @param user - obiekt uzytkownika wyszukany w application beanie
	 * @param estate - obiekt klasy Estate wyszukany w application beanie
	 */
	public boolean addComment(String title, String content, User user, Estate estate) {

        Comment comment = Comment.newComment(title, content, user, estate);
        comment = estate.addKomentarz(comment);
        if (comment != null)
        {
        	komentarze.add(comment);
        	return true;
        } else {
        	return false;
        }
    }

	public List<Comment> getEstatesComments(Estate estate) {
		return estate.getKomentarze();
	}

	public List<Comment> getUsersComments(User user) {
		return user.getKomentarze();
	}

	@Deprecated
	public Comment getComment(String title, String content, User user, Estate estate) {
		List<Comment> list = estate.getKomentarze();
		Iterator<Comment> iter = list.iterator();
		Comment comment = null;
		while(iter.hasNext()) {
			comment = iter.next();
			if(comment.getUser().equals(user) &&
				comment.getContent().equals(content) &&
				comment.getTitle().equals(title)) {

				return comment;
			}
		}

		return null;
	}

	public Comment getComment(Long commentId) {
		Iterator<Comment> iter = komentarze.iterator();
		Comment comment = null;
		while(iter.hasNext()) {
			comment = iter.next();
			if(comment.getId().equals(commentId)) {
				return comment;
			}
		}

		return null;
	}

	/* END Funkcjonalnosć komentarzy */

}
